﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;

using DataDesign.MPP.Utilities;

using PSLibrary = Microsoft.Office.Project.Server.Library;

namespace DataDesign.MPP.ServerManager
{
    public class ProjectManager
    {
        private static log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static WebSvcProject.ProjectDataSet GetAllProjectsOnServer()
        {
            try
            {
                WebSvcProject.ProjectDataSet dsProject = HelperServerManager.GetWebSvcProject().ReadProjectList();
                //WebSvcProject.ProjectDataSet dsProject = HelperServerManager.GetWebSvcProject().ReadProjectStatus(Guid.Empty, WebSvcProject.DataStoreEnum.WorkingStore, String.Empty, (int)PSLibrary.Project.ProjectType.Project);
                logger.DebugFormat("Xml of all projects: {0}", dsProject.GetXml());
                return dsProject;
            }
            catch (Exception ex)
            {
                logger.Error("ERROR GetAllProjectsOnServer", ex);
                throw;
            }
        }
        public static WebSvcProject.ProjectDataSet GetProjectByGuid(Guid guid)
        {
            try
            {

                logger.DebugFormat("Begin GetProjectByGuid. guid: {0}", guid);
                WebSvcProject.ProjectDataSet dsProject = HelperServerManager.GetWebSvcProject().ReadProject(guid, WebSvcProject.DataStoreEnum.WorkingStore);
                if (dsProject != null)
                {
                    ////logger.DebugFormat("Xml of project: {0}", dsProject.GetXml());

                    //Un-comment this code if you want to see SoapException
                    //WebSvcProject.ProjectDataSet dsProject1 = HelperAddIn.GetWebSvcProject().ReadProject(guid, WebSvcProject.DataStoreEnum.ReportingStore);                

                    return dsProject;
                }
                else
                {
                    logger.Debug("GetProjectByGuid is NULL");
                    return null;
                }
            }
            catch (Exception ex)
            {
                logger.Error("ERROR GetProjectByGuid", ex);
                HelperServerManager.LogSoapException("ERROR GetProjectByGuid", ex, logger);
                throw;
            }
        }
        

        public static List<ObjectClass.MPPProject> SearchProjectByCriteria(ObjectClass.SearchCriteria criteria)
        {
            try
            {
                logger.DebugFormat("BEGIN SearchProjectByCriteria. criteria: {0}", GenericSerialize<ObjectClass.SearchCriteria>.Serialize(criteria));

                Guid currentUserGuid = ResourceManager.GetCurrentUser().RES_UID;
                logger.DebugFormat("currentUserGuid: {0}", currentUserGuid);

                List<ObjectClass.MPPProject> list = new List<ObjectClass.MPPProject>();
                WebSvcProject.ProjectDataSet dsProject = GetAllProjectsOnServer();
                foreach (WebSvcProject.ProjectDataSet.ProjectRow prjRow in dsProject.Project)
                {
                    logger.DebugFormat("ProjectName: {0}", prjRow.PROJ_NAME);
                    if (!Common.IsNullOrWhiteSpace(criteria.ProjectName) && !prjRow.PROJ_NAME.Contains(criteria.ProjectName, StringComparison.OrdinalIgnoreCase))
                    {
                        logger.Debug("Not match ProjectName in SearchCriteria. Ignore.");
                        continue;
                    }

                    dsProject = GetProjectByGuid(prjRow.PROJ_UID);
                    if (dsProject.Project[0].ProjectOwnerID != currentUserGuid)
                    {
                        logger.Debug("Project is not belonged to this manager. Ignore.");
                        continue;
                    }

                    logger.Debug("GetMPPProject here");
                    var mppProject = GetMPPProject(dsProject);

                    logger.Debug("Check TaskName");
                    if (!Common.IsNullOrWhiteSpace(criteria.TaskName))
                    { }

                    logger.Debug("Check Customer");
                    if (!Common.IsNullOrWhiteSpace(criteria.Customer) &&
                        (Common.IsNullOrWhiteSpace(mppProject.Customer) || 
                        !mppProject.Customer.Contains(criteria.Customer, StringComparison.OrdinalIgnoreCase)))
                    {
                        logger.Debug("Not match Customer in SearchCriteria. Ignore.");
                        continue;
                    }

                    if (!mppProject.StartDate.InRange(criteria.StartDateFrom, criteria.StartDateTo))
                    {
                        logger.Debug("Not match range of StartDate in SearchCriteria. Ignore.");
                        continue;
                    }
                    if (!mppProject.FinishDate.InRange(criteria.FinishDateFrom, criteria.FinishDateTo))
                    {
                        logger.Debug("Not match range of FinishDate in SearchCriteria. Ignore.");
                        continue;
                    }
                    if (!mppProject.Progress.InRange(criteria.ProgressFrom, criteria.ProgressTo))
                    {
                        logger.Debug("Not match range of Progress in SearchCriteria. Ignore.");
                        continue;
                    }
                    if (criteria.CostType.HasValue)
                    {
                        bool bInRangeEstimate = mppProject.CostEstimate.InRange(criteria.CostFrom, criteria.CostTo);
                        bool bInRangeReal = mppProject.CostReal.InRange(criteria.CostFrom, criteria.CostTo);

                        if (criteria.CostType.Value == ObjectClass.CostEnum.Estimate && !bInRangeEstimate)
                        {
                            logger.Debug("Not match range of CostEstimate in SearchCriteria. Ignore.");
                            continue;
                        }
                        if (criteria.CostType.Value == ObjectClass.CostEnum.Real && !bInRangeReal)
                        {
                            logger.Debug("Not match range of CostReal in SearchCriteria. Ignore.");
                            continue;
                        }
                        if (criteria.CostType.Value == ObjectClass.CostEnum.Both && (!bInRangeEstimate || !bInRangeReal))
                        {
                            logger.Debug("Not match range of CostEstimate or CostReal in SearchCriteria. Ignore.");
                            continue;
                        }
                    }

                    logger.Debug("Match criteria, add project to search result");
                    list.Add(mppProject);
                }

                logger.DebugFormat("END SearchProjectByCriteria. list count: {0}", list.Count);
                return list;
            }
            catch (Exception ex)
            {
                logger.Error("ERROR SearchProjectByCriteria", ex);
                throw;
            }
        }        

        public static ObjectClass.MPPProject GetMPPProject(WebSvcProject.ProjectDataSet dsProject)
        {
            try
            {
                logger.DebugFormat("BEGIN GetMPPProject. dsProject: {0}", dsProject.GetXml());

                WebSvcProject.ProjectDataSet.ProjectRow prjRow = dsProject.Project[0];
                var mppProject = new ObjectClass.MPPProject();
                mppProject.ProjectName = prjRow.PROJ_NAME;
                mppProject.ProjectGuid = prjRow.PROJ_UID;
                mppProject.StartDate = prjRow.PROJ_INFO_START_DATE;
                mppProject.FinishDate = prjRow.PROJ_INFO_FINISH_DATE;

                var xpathDSProject = new XPathDataSet(dsProject);
                var dicPriorityLevel = HelperServerManager.DicProjectPriorityLevel;
                logger.Debug("For getting all tasks of this project, ignore the first TaskRow");
                for(int i = 1; i < dsProject.Task.Count; i++)
                {
                    var rowTask = dsProject.Task[i];
                    var mppTask = GetMPPTask(rowTask, xpathDSProject, dicPriorityLevel);                    
                    mppProject.ListTask.Add(mppTask);
                }

                int projDuration = dsProject.Task[0].TASK_DUR;
                int projActualDuration = dsProject.Task[0].TASK_ACT_DUR;
                if (projDuration > 0)
                    mppProject.Progress = (int)(projActualDuration * 100 / projDuration);

                mppProject.Customer = xpathDSProject.SelectSingleNodeValue(HelperServerManager.XPATH_PROJDS_TEXT_VALUE_BY_PROJECT_CUSTOMER);

                double num;
                if (double.TryParse(xpathDSProject.SelectSingleNodeValue(HelperServerManager.XPATH_PROJDS_TEXT_VALUE_BY_PROJECT_COST_ESTIMATE), out num))
                    mppProject.CostEstimate = num;

                if (double.TryParse(xpathDSProject.SelectSingleNodeValue(HelperServerManager.XPATH_PROJDS_TEXT_VALUE_BY_PROJECT_COST_REAL), out num))
                    mppProject.CostReal = num;

                mppProject.PriorityLevel = HelperServerManager.GetValueByDictionaryAndXPathDataSet(dicPriorityLevel, xpathDSProject, HelperServerManager.XPATH_PROJDS_CODE_VALUE_BY_PROJECT_PRIORITY_LEVEL);

                ////logger.DebugFormat("END GetMPPProject. mppProject: {0}", GenericSerialize<ObjectClass.MPPProject>.Serialize(mppProject));
                return mppProject;
            }
            catch (Exception ex)
            {
                logger.Error("ERROR GetMPPProject", ex);
                throw;
            }
        }
        
        public static ObjectClass.MPPTask GetMPPTask(WebSvcProject.ProjectDataSet.TaskRow rowTask, XPathDataSet xpathDSProject, Dictionary<Guid, string> dicPriorityLevel)
        {
            try
            {
                logger.DebugFormat("BEGIN GetMPPTask. rowTask: {0}, xpathDSProject: {1}", GenericSerialize<WebSvcProject.ProjectDataSet.TaskRow>.Serialize(rowTask), xpathDSProject.XPathNavigator.OuterXml);

                var mppTask = new ObjectClass.MPPTask();
                mppTask.TaskName = rowTask.TASK_NAME;
                mppTask.TaskGuid = rowTask.TASK_UID;
                mppTask.StartDate = rowTask.TASK_START_DATE;
                mppTask.FinishDate = rowTask.TASK_FINISH_DATE;
                mppTask.ActualDuration = rowTask.TASK_ACT_DUR;
                mppTask.Duration = rowTask.TASK_DUR;

                if (mppTask.Duration > 0)
                    mppTask.Progress = (int)(mppTask.ActualDuration * 100 / mppTask.Duration);

                mppTask.PriorityLevel = HelperServerManager.GetValueByDictionaryAndXPathDataSet(dicPriorityLevel, xpathDSProject, string.Format(HelperServerManager.XPATH_PROJDS_CODE_VALUE_BY_TASK_PRIORITY_LEVEL, mppTask.TaskGuid.ToString()));

                ////logger.DebugFormat("END GetMPPTask. mppTask: {0}", GenericSerialize<ObjectClass.MPPTask>.Serialize(mppTask));
                return mppTask;
            }
            catch (Exception ex)
            {
                logger.Error("ERROR GetMPPTask", ex);
                throw;
            }
        }
    }
}
